﻿
Imports System.Reflection

Public Class invoker(Of delegate_t)
    Private Shared ReadOnly dt As Type = Nothing
    Private ReadOnly m As delegate_t = Nothing

    Shared Sub New()
        assert(GetType(delegate_t).IsSubclassOf(GetType([Delegate])))
        dt = GetType(delegate_t)
    End Sub

    Public Sub New(ByVal t As Type, ByVal bindingFlags As BindingFlags, ByVal obj As Object, ByVal name As String)
        If Not t Is Nothing AndAlso Not isemptystring(name) Then
            Dim mi As MethodInfo = Nothing
            Try
                mi = t.GetMethod(name, bindingFlags)
            Catch ex As Exception
                raiseError(errorHandle.errorType.warning,
                           "cannot find method ", name, " in type ", t, ", ex ", ex.Message)
            End Try

            Dim d As [Delegate] = Nothing
            If Not mi Is Nothing Then
                Try
                    If mi.IsStatic() Then
                        d = [Delegate].CreateDelegate(dt, mi)
                    Else
                        d = [Delegate].CreateDelegate(dt, obj, mi)
                    End If
                Catch ex As Exception
                    raiseError(errorHandle.errorType.warning,
                               "cannot create delegate for method ", name, " in type ", t, ", ex ", ex.Message)
                End Try
            End If

            If Not d Is Nothing Then
                If Not convertor.cast(Of delegate_t)(d, m) Then
                    raiseError(errorHandle.errorType.warning,
                               "failed to convert method ", name, " in type ", t, " to delegate ", dt)
                End If
            End If
        End If
    End Sub

    Public Sub New(ByVal t As Type, ByVal bindingFlags As BindingFlags, ByVal name As String)
        Me.New(t, bindingFlags, Nothing, name)
    End Sub

    Public Sub New(ByVal t As Type, ByVal name As String)
        Me.New(t, BindingFlags.Static Or BindingFlags.Public, name)
    End Sub

    Public Sub New(ByVal t As Type, ByVal obj As Object, ByVal name As String)
        Me.New(t, BindingFlags.Static Or BindingFlags.Instance Or BindingFlags.Public, obj, name)
    End Sub

    Public Sub New(ByVal obj As Object, ByVal name As String)
        Me.New(obj.GetType(), obj, name)
    End Sub

    Public Sub New(ByVal obj As Object, ByVal bindingFlags As BindingFlags, ByVal name As String)
        Me.New(obj.GetType(), bindingFlags, obj, name)
    End Sub

    Public Sub New(ByVal bindingFlags As BindingFlags, ByVal obj As Object, ByVal name As String)
        Me.New(obj, bindingFlags, name)
    End Sub

    Public Function valid() As Boolean
        Return Not m Is Nothing
    End Function

    Public Shared Operator +(ByVal this As invoker(Of delegate_t)) As delegate_t
        If this Is Nothing OrElse Not this.valid() Then
            Return Nothing
        Else
            Return this.m
        End If
    End Operator
End Class
